﻿#include "FileUtil.h"
#include "io/File.h"
#include "collection/ArrayList.hpp"
#include "io/ByteArrayOutputStream.h"
#include "io/FileInputStream.h"
#include "io/BufferedInputStream.h"
#include "lang/StringFormat.hpp"
#include "lang/String.h"
#include <vector>
using namespace yzrilyzr_collection;
using namespace yzrilyzr_io;
using namespace yzrilyzr_array;
using namespace yzrilyzr_lang;
namespace yzrilyzr_util{
	File FileUtil::nextName(const String & file){
		File a(file);
		return nextName(a);
	}
	File FileUtil::nextName(const File & file){
		if(!file.exists()) return file;
		String name=file.getName();
		String pare=file.getParent();
		String fix="";
		int64_t index=name.lastIndexOf(".");
		if(index != -1){
			fix=name.substring(index);
			name=name.substring(0, index);
		}
		index=1;
		File tmp=file;
		while(tmp.exists()){
			tmp=File((pare + seperateChar + name + "(" + std::to_string(index) + ")" + fix));
			index++;
		}
		return tmp;
	}
	int64_t FileUtil::getFileSize(const File & path){
		if(path.isDirectory()){
			u_index siz=0;
			std::vector<File> fs=path.listFiles();
			for(File k:fs) siz+=getFileSize(k);
			return siz;
		} else return path.length();
	}
	int64_t FileUtil::getFileSize(const String & path){
		return getFileSize(File(path));
	}
	String FileUtil::readFileString(const String & path){
		auto by=readFileByte(path);
		if(by==nullptr) return "";
		String str(by);
		return str;
	}
	ByteArray FileUtil::readFileByte(const String & path){
		try{
			FileInputStream paramRegPtr(path);
			BufferedInputStream fi(paramRegPtr);
			ByteArray by(10240);
			ByteArrayOutputStream bi;
			u_index i;
			while((i=fi.read(by)) != -1) bi.write(by, 0, i);
			fi.close();
			return bi.toByteArray();
		} catch(Exception ignored){ 
			return ByteArray();
		}
	}
	String FileUtil::getFileExtension(const String & name){
		int64_t c=String(name).lastIndexOf(".");
		if(c == -1) return name;
		else if(static_cast<u_index>(c + 1) < name.length()) return String(name).substring(c + 1);
		else return "";
	}
	bool FileUtil::isGIF(const ByteArray & headerBytes){
		return (headerBytes[0] == 'G' && headerBytes[1] == 'I' && headerBytes[2] == 'F') &&
			(headerBytes[3] >= '0' && headerBytes[3] <= '9') &&
			(headerBytes[4] >= '0' && headerBytes[4] <= '9') &&
			(headerBytes[5] >= 'a' && headerBytes[5] <= 'z' || headerBytes[5] >= 'A' && headerBytes[5] <= 'Z');
	}
	String FileUtil::getFileSizeBinStr(double size){
		int i=0;
		while(size >= 1024){
			size/=1024;
			i++;
		}
		i=Math::min(i, unitCount - 1);
		return StringFormat::format("%.2f%s", size, FileSizeBiByteUnit[i]);
	}
	String FileUtil::getFileSizeDecStr(double size){
		int i=0;
		while(size >= 1000){
			size/=1000;
			i++;
		}
		i=Math::min(i, unitCount - 1);
		return StringFormat::format("%.2f%s", size, FileSizeByteUnit[i]);
	}
	String FileUtil::abs(const String & p1){
		String p=p1;
		p=normalize(p);
		while(p.contains(currentDir)) p=p.replace(currentDir, seperateChar);
		while(p.contains("..")){
			int64_t ind=p.indexOf("..");
			String a=p.substring(0, ind);
			String b=parent(a);
			if(a == b) return "";
			p=b.concat(p.substring(ind + 2));
		}
		return normalize(p);
	}
	String FileUtil::normalize(const String & p1){
		String p=p1;
		p=p.replace("\\", seperateChar);
		if(!p.startsWith(seperateChar)) p=String(seperateChar).concat(p);
		while(p.contains(doubleSeperateChar)) p=p.replace(doubleSeperateChar, seperateChar);
		while(p.contains("...")) p=p.replace("...", "..");
		if(p.length() != 1 && p.endsWith(seperateChar)) p=p.substring(0, p.length() - 1);
		if(p == "") return seperateChar;
		return p;
	}
	String FileUtil::parent(const String & p1){
		String p=p1;
		p=normalize(p);
		int64_t ind=p.lastIndexOf(seperateChar);
		if(ind == -1) return seperateChar;
		return normalize(p.substring(0, ind));
	}
	String FileUtil::name(const String & p1){
		String p=p1;
		p=normalize(p);
		int64_t ind=p.lastIndexOf(seperateChar);
		if(ind == -1) return p;
		return p.substring(ind + 1);
	}
	void FileUtil::mkdirs(const String & path){
		mkdirs(File(path));
	}
	void FileUtil::mkdirs(const File & f){
		if(!f.isDirectory()) f.deleteFile();
		if(!f.exists()) f.mkdirs();
	}
}